﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using SlimDX.Direct3D10;
using SlimDX.DXGI;
namespace System.Windows.Media.Media3D10
{
    /// <summary>
    /// Geometry 3-D pour générer une forme 3-D. 
    /// </summary>
    public sealed class MeshGeometry3D10 : Geometry3D10
    {
        #region Dependency Properties
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="Normals"/>.
        /// </summary>
        public static readonly DependencyProperty NormalsProperty =
            DependencyProperty.Register("Normals", typeof(Vector3Collection), typeof(MeshGeometry3D10));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="Positions"/>.
        /// </summary>
        public static readonly DependencyProperty PositionsProperty =
            DependencyProperty.Register("Positions", typeof(Vector3Collection), typeof(MeshGeometry3D10));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="TextureCoordinates"/>.
        /// </summary>
        public static readonly DependencyProperty TextureCoordinatesProperty =
            DependencyProperty.Register("TextureCoordinates", typeof(Vector2Collection), typeof(MeshGeometry3D10));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="TriangleIndices"/>.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1726")]        
        public static readonly DependencyProperty TriangleIndicesProperty =
            DependencyProperty.Register("TriangleIndices", typeof(Int32Collection), typeof(MeshGeometry3D10));
        #endregion
        
        #region Constructors
        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="MeshGeometry3D10"/>
        /// </summary>
        public MeshGeometry3D10()
        {
            this.Normals = new Vector3Collection();
            this.Positions = new Vector3Collection();
            this.TextureCoordinates = new Vector2Collection();
            this.TriangleIndices = new Int32Collection();
        }
        #endregion

        #region Data
        private static readonly InputElement[] _inputElements = new[] 
            {
                new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0), 
                new InputElement("NORMAL", 0, Format.R32G32B32_Float, 0, 1), 
                new InputElement("TEXCOORD", 0, Format.R32G32_Float, 0, 2)
            };
        private VertexBufferBinding[] _binding;
        #endregion

        #region Public Properties
        /// <summary>
        /// Obtient ou définit une collection de vecteurs normaux pour <see cref="MeshGeometry3D10"/>. 
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage","CA2227")]
        public Vector3Collection Normals
        {
            get { return (Vector3Collection)GetValue(NormalsProperty); }
            set { SetValue(NormalsProperty, value); }
        }

        /// <summary>
        /// Obtient ou définit une collection de positions de vertex pour <see cref="MeshGeometry3D10"/>. 
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227")]
        public Vector3Collection Positions
        {
            get { return (Vector3Collection)GetValue(PositionsProperty); }
            set { SetValue(PositionsProperty, value); }
        }

        /// <summary>
        /// Obtient ou définit une collection de coordonnées de texture pour <see cref="MeshGeometry3D10"/>. 
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227")]
        public Vector2Collection TextureCoordinates
        {
            get { return (Vector2Collection)GetValue(TextureCoordinatesProperty); }
            set { SetValue(TextureCoordinatesProperty, value); }
        }

        /// <summary>
        /// Obtient ou définit une collection d'indices de triangle pour <see cref="MeshGeometry3D10"/>. 
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1726")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227")]
        public Int32Collection TriangleIndices
        {
            get { return (Int32Collection)GetValue(TriangleIndicesProperty); }
            set { SetValue(TriangleIndicesProperty, value); }
        }
        #endregion

        #region Geometry3D10 Implementation
        /// <summary>
        /// Obtient un tableau de <see cref="InputElement"/> utilisables avec ce <see cref="Geometry3D10"/>
        /// </summary>
        /// <returns>Retourne les <see cref="InputElement"/> utilisables avec ce <see cref="Geometry3D10"/></returns>
        public override InputElement[] GetInputElements()
        {
            return _inputElements;
        }

        /// <summary>
        /// Obtient le <see cref="VertexBufferBinding"/> par défaut de ce <see cref="Geometry3D10"/>
        /// </summary>
        /// <returns>Retourne le <see cref="VertexBufferBinding"/> par défaut de ce <see cref="Geometry3D10"/></returns>
        public override VertexBufferBinding[] GetVertexBufferBinding()
        {
            if (!IsFrozen)
                throw new InvalidOperationException("VertexBufferBinding is only available after freeze");
            return _binding;
        }
        #endregion

        #region Freezable Overrides
        /// <summary>
        /// Rend l'objet <see cref="Freezable"/> non modifiable ou vérifie si celui-ci peut être rendu non modifiable ou pas.
        /// </summary>
        /// <param name="isChecking">true pour retourner une indication de la possibilité ou non de figer l'objet (sans le figer réellement) ; false pour figer réellement l'objet.</param>
        /// <returns>
        /// Si <paramref name="isChecking"/> est true, cette méthode retourne true si le <see cref="Freezable"/> peut être rendu non modifiable, ou false si cette opération est impossible.
        /// Si <paramref name="isChecking"/> est false, cette méthode retourne true si le <see cref="Freezable"/> spécifié est désormais non modifiable, ou false si cette opération est impossible.
        /// </returns>
        protected override bool FreezeCore(bool isChecking)
        {
            bool returnValue = base.FreezeCore(isChecking);
            if (!isChecking)
            {
                this.Positions.Freeze();
                this.Normals.Freeze();
                this.TextureCoordinates.Freeze();
                this.TriangleIndices.Freeze();

                _binding = new[]
                    {
                        new SlimDX.Direct3D10.VertexBufferBinding(Positions.Buffer, Marshal.SizeOf(typeof(SlimDX.Vector3)), 0),
                        new SlimDX.Direct3D10.VertexBufferBinding(Normals.Buffer, Marshal.SizeOf(typeof(SlimDX.Vector3)), 0),
                        new SlimDX.Direct3D10.VertexBufferBinding(TextureCoordinates.Buffer, Marshal.SizeOf(typeof(SlimDX.Vector2)), 0)
                    };
            }
            return returnValue;
        }
        #endregion

        #region Freezable Implementation
        /// <summary>
        /// Une fois implémentée dans une classe dérivée, initialise une nouvelle instance de la classe dérivée <see cref="Freezable"/>. 
        /// </summary>
        /// <returns>Nouvelle instance.</returns>
        protected override Freezable CreateInstanceCore()
        {
            return new MeshGeometry3D10();
        }
        #endregion
    }
}
